//-----------------------------------------------------------------------------
// building.cpp
//-----------------------------------------------------------------------------

#include "AReVi/arClass.h"
#include "AReVi/arSystem.h"
#include "AReVi/Shapes/shape3D.h"
#include "AReVi/Shapes/mesh3D.h"
#include "AReVi/Lib3D/object3D.h"
#include "AReVi/Lib3D/transform2D.h"
#include "AReVi/Lib3D/urlTexture.h"
#include "AReVi/Utils/abstractStream.h"

// #include "AReVi/VRML/vrmlShape3D.h"
using namespace AReVi;

#include "building.h"
//----------------------------------------------------------------------------

AR_CLASS_DEF(Building,Element)

//----------------------------------------------------------------------------

Building::Building(ArCW & arCW):
Element(arCW),
  _representation(Object3D::NEW()),
  _sideWalk(Mesh3D::NEW()),
  _facade(Mesh3D::NEW()),
  _windows(Mesh3D::NEW()),
  _roof(Mesh3D::NEW()),
  _sx(1.0),
  _sy(1.0),
  _sz(1.0),
  _fh(10.0),
  _swHeigth(1.0),
  _swWidth(1.0)
{
  _computeSideWalk();
  _computeBuilding();

  ArRef<Shape3D> sh = Shape3D::NEW();
  sh->addRootPart(_sideWalk);
  sh->addRootPart(_facade);
  sh->addRootPart(_windows);
  sh->addRootPart(_roof);

  _representation->setShape(sh);
}

Building::~Building() {}

//----------------------------------------------------------------------------

void Building::init() {
}


void Building::writeConfiguration(ArRef<AbstractOStream> stream) {
  stream->writeDouble(_sx);
  stream->writeDouble(_sy);
  stream->writeDouble(_sz);
  stream->writeDouble(_fh);
  stream->writeDouble(_swHeigth);
  stream->writeDouble(_swWidth);
}

void Building::readConfiguration(ArRef<AbstractIStream> stream) {
  stream->readDouble(_sx);
  stream->readDouble(_sy);
  stream->readDouble(_sz);
  stream->readDouble(_fh);
  stream->readDouble(_swHeigth);
  stream->readDouble(_swWidth);
  _computeSideWalk();
  _computeBuilding();
}



void Building::writeUpdate(ArRef<AbstractOStream>) {
}

void Building::readUpdate(ArRef<AbstractIStream>) {
}


//------------------------------


bool
Building::setSideWalkGeometry(double width, double heigth){
  if(width>=0.0 && heigth >= 0.0) {
    _swWidth = width;
    _swHeigth = heigth;
    _computeSideWalk();
    return true;
  }
  else return false;
}

void
Building::getSideWalkGeometry(double & width, double & heigth){
  width = _swWidth;
  heigth = _swHeigth;
}

//----------------------------------------------------------------------------

bool
Building::setSize(double sx, double sy, double sz) {
  if(sx >0.0 && sy > 0.0 && sz > 0.0){
    _sx = sx;
    _sy = sy;
    _sz = sz;
    _computeSideWalk();
    _computeBuilding();

    return true;
  }
  else return false;
}

void
Building::getSize(double & sx, double & sy, double & sz) {
  sx = _sx;
  sy = _sy;
  sz = _sz;
}

bool
Building::setFacadeHeight(double fh) {
  if(fh > 0.0 && fh < _sz) {
    _fh = fh;
    _computeBuilding();

    return true;
  }
  else return false;
}

double
Building::getFacadeHeight(void) {
  return _fh;
}

//----------------------------------------------------------------------------

void
Building::_computeSideWalk(void) {

  _sideWalk->accessVertices().clear();

  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),0));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),0));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),(_sy/2.0+_swWidth),0));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),(_sy/2.0+_swWidth),0));

  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),_swHeigth));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),_swHeigth));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),(_sy/2.0+_swWidth),_swHeigth));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),(_sy/2.0+_swWidth),_swHeigth));


  _sideWalk->accessVertexFaces().clear();
  _sideWalk->accessTextureFaces().clear();

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(0,1,5));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(0,5,4));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(1,2,6));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(1,6,5));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(2,3,7));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(2,7,6));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(3,0,4));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(3,4,7));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(5,6,7));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(5,7,4));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessTextures().clear();

  _sideWalk->accessTextures().push_back(Util3D::Dbl2(0.0,0.0));
  _sideWalk->accessTextures().push_back(Util3D::Dbl2(1.0,0.0));
  _sideWalk->accessTextures().push_back(Util3D::Dbl2(1.0,1.0));
  _sideWalk->accessTextures().push_back(Util3D::Dbl2(0.0,1.0));

  _sideWalk->computeDefaultNormals(false);

  _sideWalk->applyChanges(false);

  ArRef<Transform2D> tr = Transform2D::NEW();
  tr->preScale((_sy/2.0+_swWidth)/5.0,(_sx/2.0+_swWidth)/5.0);
  _sideWalk->writeTextureTransformation(tr);
  _sideWalk->setTexture(URLTexture::NEW("./models/textures/cement_002.jpg",true,true));

}

void
Building::_computeBuilding(void) {
  _facade->accessVertices().clear();

  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),0));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),0));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),0));
  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),0));

  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_fh));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_fh));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_fh));
  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_fh));


  _facade->accessVertexFaces().clear();
  _facade->accessTextureFaces().clear();

  _facade->accessVertexFaces().push_back(Util3D::Face(0,1,5));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(0,5,4));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessVertexFaces().push_back(Util3D::Face(1,2,6));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(1,6,5));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessVertexFaces().push_back(Util3D::Face(2,3,7));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(2,7,6));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessVertexFaces().push_back(Util3D::Face(3,0,4));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(3,4,7));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessTextures().clear();

  _facade->accessTextures().push_back(Util3D::Dbl2(0.0,0.0));
  _facade->accessTextures().push_back(Util3D::Dbl2(1.0,0.0));
  _facade->accessTextures().push_back(Util3D::Dbl2(1.0,1.0));
  _facade->accessTextures().push_back(Util3D::Dbl2(0.0,1.0));


  _facade->computeDefaultNormals(false);

  _facade->applyChanges(false);

  ArRef<Transform2D> tr = Transform2D::NEW();
  tr->preScale( (_sx+_sy)/(2.0*50.0),1);
  _facade->writeTextureTransformation(tr);
  _facade->setTexture(URLTexture::NEW("./models/textures/facade.jpg",true,true));


  _windows->accessVertices().clear();

  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_fh));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_fh));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_fh));
  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_fh));

  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_sz));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_sz));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_sz));
  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_sz));


  _windows->accessVertexFaces().clear();
  _windows->accessTextureFaces().clear();

  _windows->accessVertexFaces().push_back(Util3D::Face(0,1,5));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(0,5,4));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessVertexFaces().push_back(Util3D::Face(1,2,6));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(1,6,5));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessVertexFaces().push_back(Util3D::Face(2,3,7));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(2,7,6));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessVertexFaces().push_back(Util3D::Face(3,0,4));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(3,4,7));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessTextures().clear();

  _windows->accessTextures().push_back(Util3D::Dbl2(0.0,0.0));
  _windows->accessTextures().push_back(Util3D::Dbl2(1.0,0.0));
  _windows->accessTextures().push_back(Util3D::Dbl2(1.0,1.0));
  _windows->accessTextures().push_back(Util3D::Dbl2(0.0,1.0));

  _windows->computeDefaultNormals(false);

  _windows->applyChanges(false);

  ArRef<Transform2D> tr2 = Transform2D::NEW();
  tr2->preScale((_sx + _sy + 2.0*_swWidth )/(2.0*50.0),(_sz-_fh)/10.0);
  _windows->writeTextureTransformation(tr2);
  _windows->setTexture(URLTexture::NEW("./models/textures/windows.jpg",true,true));

  _roof->accessVertices().clear();

  _roof->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_sz));
  _roof->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_sz));
  _roof->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_sz));
  _roof->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_sz));


  _roof->accessVertexFaces().clear();
  _roof->accessTextureFaces().clear();

  _roof->accessVertexFaces().clear();

  _roof->accessVertexFaces().push_back(Util3D::Face(0,1,2));
  _roof->accessVertexFaces().push_back(Util3D::Face(0,2,3));

  _roof->computeDefaultNormals(false);

  _roof->applyChanges(false);

}
